//! 文件操作工具模块
//! 
//! 对应Java中的AppFileMgr类，提供文件和目录操作功能

use std::fs::{self, File, OpenOptions, metadata};
use std::io::{self, Write, BufRead, BufReader, BufWriter};
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use base64::{Engine as _, engine::general_purpose};

/// 文件操作错误类型
#[derive(Debug, thiserror::Error)]
pub enum FileError {
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    #[error("Base64 decode error: {0}")]
    Base64Decode(#[from] base64::DecodeError),
    #[error("File not found: {path}")]
    FileNotFound { path: String },
    #[error("Invalid path: {path}")]
    InvalidPath { path: String },
}

pub type FileResult<T> = Result<T, FileError>;

/// 检查文件是否存在
/// 
/// # Examples
/// ```
/// use librarys::file_utils::file_exists;
/// use std::fs::File;
/// 
/// // 创建一个临时文件用于测试
/// File::create("test_file.txt").unwrap();
/// assert_eq!(file_exists("test_file.txt"), true);
/// assert_eq!(file_exists("nonexistent.txt"), false);
/// std::fs::remove_file("test_file.txt").unwrap();
/// ```
pub fn file_exists<P: AsRef<Path>>(path: P) -> bool {
    path.as_ref().exists()
}

/// 检查文件是否存在且符合时间戳要求
/// 
/// # Examples
/// ```
/// use librarys::file_utils::file_exists_with_timestamp;
/// use std::fs::File;
/// use std::time::{SystemTime, Duration};
/// 
/// File::create("test_file.txt").unwrap();
/// let now = SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
/// assert_eq!(file_exists_with_timestamp("test_file.txt", Some(now)), true);
/// std::fs::remove_file("test_file.txt").unwrap();
/// ```
pub fn file_exists_with_timestamp<P: AsRef<Path>>(path: P, timestamp: Option<u64>) -> bool {
    let path = path.as_ref();
    if !path.exists() {
        return false;
    }
    
    if let Some(ts) = timestamp {
        if let Ok(metadata) = metadata(path) {
            if let Ok(modified) = metadata.modified() {
                if let Ok(duration) = modified.duration_since(SystemTime::UNIX_EPOCH) {
                    let file_timestamp = duration.as_secs();
                    // 允许60秒的误差
                    return file_timestamp >= ts.saturating_sub(60);
                }
            }
        }
    }
    
    true
}

/// 获取文件大小（字节）
/// 
/// # Examples
/// ```
/// use librarys::file_utils::get_file_size;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// let mut file = File::create("test_size.txt").unwrap();
/// file.write_all(b"hello world").unwrap();
/// assert_eq!(get_file_size("test_size.txt").unwrap(), 11);
/// std::fs::remove_file("test_size.txt").unwrap();
/// ```
pub fn get_file_size<P: AsRef<Path>>(path: P) -> FileResult<u64> {
    let metadata = fs::metadata(path)?;
    Ok(metadata.len())
}

/// 递归获取目录大小（字节）
/// 
/// # Examples
/// ```
/// use librarys::file_utils::get_dir_size;
/// use std::fs::{self, File};
/// use std::io::Write;
/// 
/// fs::create_dir_all("test_dir").unwrap();
/// let mut file = File::create("test_dir/file1.txt").unwrap();
/// file.write_all(b"hello").unwrap();
/// let mut file2 = File::create("test_dir/file2.txt").unwrap();
/// file2.write_all(b"world").unwrap();
/// 
/// let size = get_dir_size("test_dir").unwrap();
/// assert_eq!(size, 10); // "hello" + "world" = 10 bytes
/// fs::remove_dir_all("test_dir").unwrap();
/// ```
pub fn get_dir_size<P: AsRef<Path>>(path: P) -> FileResult<u64> {
    let path = path.as_ref();
    if !path.is_dir() {
        return get_file_size(path);
    }
    
    let mut total_size = 0;
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let entry_path = entry.path();
        if entry_path.is_dir() {
            total_size += get_dir_size(&entry_path)?;
        } else {
            total_size += get_file_size(&entry_path)?;
        }
    }
    
    Ok(total_size)
}

/// 删除文件或目录（递归删除）
/// 
/// # Examples
/// ```
/// use librarys::file_utils::delete_file_or_dir;
/// use std::fs::{self, File};
/// 
/// File::create("test_delete.txt").unwrap();
/// assert!(delete_file_or_dir("test_delete.txt").is_ok());
/// 
/// fs::create_dir_all("test_delete_dir/subdir").unwrap();
/// File::create("test_delete_dir/file.txt").unwrap();
/// assert!(delete_file_or_dir("test_delete_dir").is_ok());
/// ```
pub fn delete_file_or_dir<P: AsRef<Path>>(path: P) -> FileResult<()> {
    let path = path.as_ref();
    if path.is_dir() {
        fs::remove_dir_all(path)?;
    } else if path.exists() {
        fs::remove_file(path)?;
    }
    Ok(())
}

/// 读取文件内容为字符串
/// 
/// # Examples
/// ```
/// use librarys::file_utils::read_file_to_string;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// let mut file = File::create("test_read.txt").unwrap();
/// file.write_all(b"Hello, World!").unwrap();
/// 
/// let content = read_file_to_string("test_read.txt").unwrap();
/// assert_eq!(content, "Hello, World!");
/// std::fs::remove_file("test_read.txt").unwrap();
/// ```
pub fn read_file_to_string<P: AsRef<Path>>(path: P) -> FileResult<String> {
    Ok(fs::read_to_string(path)?)
}

/// 读取文件内容为字节数组
/// 
/// # Examples
/// ```
/// use librarys::file_utils::read_file_to_bytes;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// let mut file = File::create("test_read_bytes.txt").unwrap();
/// file.write_all(b"Hello").unwrap();
/// 
/// let bytes = read_file_to_bytes("test_read_bytes.txt").unwrap();
/// assert_eq!(bytes, b"Hello");
/// std::fs::remove_file("test_read_bytes.txt").unwrap();
/// ```
pub fn read_file_to_bytes<P: AsRef<Path>>(path: P) -> FileResult<Vec<u8>> {
    Ok(fs::read(path)?)
}

/// 将字符串写入文件
/// 
/// # Examples
/// ```
/// use librarys::file_utils::write_string_to_file;
/// use std::fs;
/// 
/// write_string_to_file("test_write.txt", "Hello, Rust!", false).unwrap();
/// let content = fs::read_to_string("test_write.txt").unwrap();
/// assert_eq!(content, "Hello, Rust!");
/// fs::remove_file("test_write.txt").unwrap();
/// ```
pub fn write_string_to_file<P: AsRef<Path>>(
    path: P, 
    content: &str, 
    append: bool
) -> FileResult<()> {
    let path = path.as_ref();
    
    // 确保父目录存在
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    
    let file = if append {
        OpenOptions::new().create(true).append(true).open(path)?
    } else {
        File::create(path)?
    };
    
    let mut writer = BufWriter::new(file);
    writer.write_all(content.as_bytes())?;
    writer.flush()?;
    
    Ok(())
}

/// 将字节数组写入文件
/// 
/// # Examples
/// ```
/// use librarys::file_utils::write_bytes_to_file;
/// use std::fs;
/// 
/// write_bytes_to_file("test_write_bytes.txt", b"Hello", false).unwrap();
/// let content = fs::read("test_write_bytes.txt").unwrap();
/// assert_eq!(content, b"Hello");
/// fs::remove_file("test_write_bytes.txt").unwrap();
/// ```
pub fn write_bytes_to_file<P: AsRef<Path>>(
    path: P, 
    content: &[u8], 
    append: bool
) -> FileResult<()> {
    let path = path.as_ref();
    
    // 确保父目录存在
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    
    let file = if append {
        OpenOptions::new().create(true).append(true).open(path)?
    } else {
        File::create(path)?
    };
    
    let mut writer = BufWriter::new(file);
    writer.write_all(content)?;
    writer.flush()?;
    
    Ok(())
}

/// 逐行读取文件
/// 
/// # Examples
/// ```
/// use librarys::file_utils::read_lines;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// let mut file = File::create("test_lines.txt").unwrap();
/// file.write_all(b"line1\nline2\nline3").unwrap();
/// 
/// let lines = read_lines("test_lines.txt").unwrap();
/// assert_eq!(lines, vec!["line1", "line2", "line3"]);
/// std::fs::remove_file("test_lines.txt").unwrap();
/// ```
pub fn read_lines<P: AsRef<Path>>(path: P) -> FileResult<Vec<String>> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);
    let mut lines = Vec::new();
    
    for line in reader.lines() {
        lines.push(line?);
    }
    
    Ok(lines)
}

/// 复制文件
/// 
/// # Examples
/// ```
/// use librarys::file_utils::copy_file;
/// use std::fs::{self, File};
/// use std::io::Write;
/// 
/// let mut file = File::create("test_source.txt").unwrap();
/// file.write_all(b"source content").unwrap();
/// 
/// copy_file("test_source.txt", "test_dest.txt").unwrap();
/// let dest_content = fs::read_to_string("test_dest.txt").unwrap();
/// assert_eq!(dest_content, "source content");
/// 
/// fs::remove_file("test_source.txt").unwrap();
/// fs::remove_file("test_dest.txt").unwrap();
/// ```
pub fn copy_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dest: Q) -> FileResult<()> {
    let dest = dest.as_ref();
    
    // 确保目标目录存在
    if let Some(parent) = dest.parent() {
        fs::create_dir_all(parent)?;
    }
    
    fs::copy(src, dest)?;
    Ok(())
}

/// 移动/重命名文件
/// 
/// # Examples
/// ```
/// use librarys::file_utils::move_file;
/// use std::fs::{self, File};
/// use std::io::Write;
/// 
/// let mut file = File::create("test_move_src.txt").unwrap();
/// file.write_all(b"move content").unwrap();
/// 
/// move_file("test_move_src.txt", "test_move_dest.txt").unwrap();
/// assert!(!fs::metadata("test_move_src.txt").is_ok());
/// assert_eq!(fs::read_to_string("test_move_dest.txt").unwrap(), "move content");
/// 
/// fs::remove_file("test_move_dest.txt").unwrap();
/// ```
pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dest: Q) -> FileResult<()> {
    let dest = dest.as_ref();
    
    // 确保目标目录存在
    if let Some(parent) = dest.parent() {
        fs::create_dir_all(parent)?;
    }
    
    fs::rename(src, dest)?;
    Ok(())
}

/// 创建目录（递归创建）
/// 
/// # Examples
/// ```
/// use librarys::file_utils::create_dir_all;
/// use std::fs;
/// 
/// create_dir_all("test_dir/sub1/sub2").unwrap();
/// assert!(fs::metadata("test_dir/sub1/sub2").unwrap().is_dir());
/// fs::remove_dir_all("test_dir").unwrap();
/// ```
pub fn create_dir_all<P: AsRef<Path>>(path: P) -> FileResult<()> {
    fs::create_dir_all(path)?;
    Ok(())
}

/// 获取文件名（不包含目录）
/// 
/// # Examples
/// ```
/// use librarys::file_utils::get_filename;
/// 
/// assert_eq!(get_filename("file.txt"), "file.txt");
/// // On Windows: C:\\path\\to\\file.txt, On Unix: /path/to/file.txt
/// #[cfg(unix)]
/// assert_eq!(get_filename("/path/to/file.txt"), "file.txt");
/// #[cfg(windows)]
/// assert_eq!(get_filename("C:\\\\path\\\\to\\\\file.txt"), "file.txt");
/// assert_eq!(get_filename(""), "");
/// ```
pub fn get_filename<P: AsRef<Path>>(path: P) -> String {
    path.as_ref()
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or("")
        .to_string()
}

/// 获取文件扩展名
/// 
/// # Examples
/// ```
/// use librarys::file_utils::get_file_extension;
/// 
/// assert_eq!(get_file_extension("file.txt"), Some("txt".to_string()));
/// assert_eq!(get_file_extension("file.tar.gz"), Some("gz".to_string()));
/// assert_eq!(get_file_extension("file"), None);
/// ```
pub fn get_file_extension<P: AsRef<Path>>(path: P) -> Option<String> {
    path.as_ref()
        .extension()
        .and_then(|ext| ext.to_str())
        .map(|ext| ext.to_string())
}

/// 文件转Base64编码
/// 
/// # Examples
/// ```no_run
/// use librarys::file_utils::file_to_base64;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// let mut file = File::create("test_base64.txt").unwrap();
/// file.write_all(b"Hello").unwrap();
/// 
/// let base64_str = file_to_base64("test_base64.txt").unwrap();
/// assert_eq!(base64_str, "SGVsbG8=");
/// std::fs::remove_file("test_base64.txt").unwrap();
/// ```
pub fn file_to_base64<P: AsRef<Path>>(path: P) -> FileResult<String> {
    let bytes = read_file_to_bytes(path)?;
    Ok(general_purpose::STANDARD.encode(&bytes))
}

/// Base64字符串解码保存为文件
/// 
/// # Examples
/// ```no_run
/// use librarys::file_utils::base64_to_file;
/// use std::fs;
/// 
/// base64_to_file("SGVsbG8=", "test_decode.txt").unwrap();
/// let content = fs::read_to_string("test_decode.txt").unwrap();
/// assert_eq!(content, "Hello");
/// fs::remove_file("test_decode.txt").unwrap();
/// ```
pub fn base64_to_file<P: AsRef<Path>>(base64_str: &str, path: P) -> FileResult<()> {
    let bytes = general_purpose::STANDARD.decode(base64_str)?;
    write_bytes_to_file(path, &bytes, false)?;
    Ok(())
}

/// 列出目录内容
/// 
/// # Examples
/// ```no_run
/// use librarys::file_utils::list_dir;
/// use std::fs::{self, File};
/// 
/// fs::create_dir_all("test_list").unwrap();
/// File::create("test_list/file1.txt").unwrap();
/// File::create("test_list/file2.txt").unwrap();
/// fs::create_dir("test_list/subdir").unwrap();
/// 
/// let entries = list_dir("test_list").unwrap();
/// assert_eq!(entries.len(), 3);
/// 
/// fs::remove_dir_all("test_list").unwrap();
/// ```
pub fn list_dir<P: AsRef<Path>>(path: P) -> FileResult<Vec<PathBuf>> {
    let mut entries = Vec::new();
    
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        entries.push(entry.path());
    }
    
    entries.sort();
    Ok(entries)
}

/// 获取可读的文件大小描述
/// 
/// # Examples
/// ```
/// use librarys::file_utils::format_file_size;
/// 
/// assert_eq!(format_file_size(1024), "1.0 KB");
/// assert_eq!(format_file_size(1536), "1.5 KB");
/// assert_eq!(format_file_size(1048576), "1.0 MB");
/// ```
pub fn format_file_size(size: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    let mut size = size as f64;
    let mut unit_index = 0;
    
    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
        size /= 1024.0;
        unit_index += 1;
    }
    
    if unit_index == 0 {
        format!("{} {}", size as u64, UNITS[unit_index])
    } else {
        format!("{:.1} {}", size, UNITS[unit_index])
    }
}

/// 检查文件是否为空
/// 
/// # Examples
/// ```no_run
/// use librarys::file_utils::is_file_empty;
/// use std::fs::File;
/// use std::io::Write;
/// 
/// File::create("test_empty.txt").unwrap();
/// assert_eq!(is_file_empty("test_empty.txt").unwrap(), true);
/// 
/// let mut file = File::create("test_nonempty.txt").unwrap();
/// file.write_all(b"content").unwrap();
/// assert_eq!(is_file_empty("test_nonempty.txt").unwrap(), false);
/// 
/// std::fs::remove_file("test_empty.txt").unwrap();
/// std::fs::remove_file("test_nonempty.txt").unwrap();
/// ```
pub fn is_file_empty<P: AsRef<Path>>(path: P) -> FileResult<bool> {
    let size = get_file_size(path)?;
    Ok(size == 0)
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn test_file_operations() {
        let temp_dir = tempdir().unwrap();
        let file_path = temp_dir.path().join("test.txt");
        let content = "Hello, World!";
        
        // 测试写入
        write_string_to_file(&file_path, content, false).unwrap();
        assert!(file_exists(&file_path));
        
        // 测试读取
        let read_content = read_file_to_string(&file_path).unwrap();
        assert_eq!(read_content, content);
        
        // 测试文件大小
        let size = get_file_size(&file_path).unwrap();
        assert_eq!(size, content.len() as u64);
        
        // 测试是否为空
        assert!(!is_file_empty(&file_path).unwrap());
    }

    #[test]
    fn test_directory_operations() {
        let temp_dir = tempdir().unwrap();
        let sub_dir = temp_dir.path().join("subdir");
        
        // 测试创建目录
        create_dir_all(&sub_dir).unwrap();
        assert!(sub_dir.exists());
        
        // 创建一些文件
        write_string_to_file(sub_dir.join("file1.txt"), "content1", false).unwrap();
        write_string_to_file(sub_dir.join("file2.txt"), "content2", false).unwrap();
        
        // 测试列出目录
        let entries = list_dir(&sub_dir).unwrap();
        assert_eq!(entries.len(), 2);
        
        // 测试目录大小
        let dir_size = get_dir_size(&sub_dir).unwrap();
        assert_eq!(dir_size, 16); // "content1" + "content2" = 16 bytes
    }

    #[test]
    fn test_copy_and_move() {
        let temp_dir = tempdir().unwrap();
        let src_path = temp_dir.path().join("source.txt");
        let copy_path = temp_dir.path().join("copy.txt");
        let move_path = temp_dir.path().join("moved.txt");
        
        // 创建源文件
        write_string_to_file(&src_path, "test content", false).unwrap();
        
        // 测试复制
        copy_file(&src_path, &copy_path).unwrap();
        assert!(file_exists(&copy_path));
        assert_eq!(read_file_to_string(&copy_path).unwrap(), "test content");
        
        // 测试移动
        move_file(&src_path, &move_path).unwrap();
        assert!(!file_exists(&src_path));
        assert!(file_exists(&move_path));
        assert_eq!(read_file_to_string(&move_path).unwrap(), "test content");
    }

    #[test]
    fn test_base64_operations() {
        let temp_dir = tempdir().unwrap();
        let file_path = temp_dir.path().join("base64_test.txt");
        let content = "Hello, Base64!";
        
        // 写入文件
        write_string_to_file(&file_path, content, false).unwrap();
        
        // 转换为Base64
        let base64_str = file_to_base64(&file_path).unwrap();
        
        // 从Base64恢复
        let decode_path = temp_dir.path().join("decoded.txt");
        base64_to_file(&base64_str, &decode_path).unwrap();
        
        // 验证内容
        let decoded_content = read_file_to_string(&decode_path).unwrap();
        assert_eq!(decoded_content, content);
    }

    #[test]
    fn test_utility_functions() {
        assert_eq!(get_filename("/path/to/file.txt"), "file.txt");
        assert_eq!(get_file_extension("file.txt"), Some("txt".to_string()));
        assert_eq!(get_file_extension("file"), None);
        
        assert_eq!(format_file_size(1024), "1.0 KB");
        assert_eq!(format_file_size(1048576), "1.0 MB");
    }
}